// G4提供的头文件
#include "G4HCofThisEvent.hh"
#include "G4Step.hh"
#include "G4ThreeVector.hh"
#include "G4SDManager.hh"
#include "G4ios.hh"
#include "G4EventManager.hh"
#include "G4AnalysisManager.hh"
// 用户定义的头文件
#include "G4ImproveSD.hh"
#include "G4ImproveHit.hh"
#include "G4ImproveEventAction.hh"

// 构造函数.初始化一个敏感探测器实例，并 注册一个命中集合的名字
G4ImproveSD::G4ImproveSD(const G4String& name,const G4String& hitsCollectionName)
:G4VSensitiveDetector(name){
    collectionName.insert(hitsCollectionName);
}

// Sensitive Detector中，每发生一次step，该函数执行一次，用于获取该步骤的信息。
G4bool G4ImproveSD::ProcessHits(G4Step* aStep,G4TouchableHistory*){

    // 获取本次event的ID
    G4int eventID = G4EventManager::GetEventManager()->GetNonconstCurrentEvent()->GetEventID();

    // 获取当前步骤（step）的能量沉积
    G4double edep = aStep->GetTotalEnergyDeposit();
    if(edep == 0.0) return false;       // 如果当前步骤中的能量沉积为零，则直接返回 false，表示该步骤不会产生命中，也不需要进一步处理。

    // 创建一个新的命中对象
    auto newHit = new G4ImproveHit();

    // 将eventID设置到Hit中
    newHit->SetEventID(eventID);
    // 获取粒子的轨迹 ID，并将其存储到命中对象中
    newHit->SetTrackID(aStep->GetTrack()->GetTrackID());
    // 获取当前步骤所在的几何体的副本号，并将其存储到命中对象中
    newHit->SetChamberNb(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber());
    // 获取当前步骤的能量沉积
    newHit->SetEdep(edep);
    // 记录当前步骤结束时的位置
    G4ThreeVector particlePos = aStep->GetPostStepPoint()->GetPosition();
    newHit->SetPos(particlePos);

    // 将本次Hit添加到HitCollection中（insert方法），本次Hit获得到的信息也同样被储存。
    fHitsCollection->insert(newHit);

    auto analysisManager = G4AnalysisManager::Instance();

    analysisManager->FillNtupleDColumn(0,edep);                 // 第一个Ntuple存放能量沉积
    analysisManager->FillNtupleDColumn(1,particlePos.x());      // 第二个Ntuple存放能量粒子的x坐标
    analysisManager->FillNtupleDColumn(2,particlePos.y());      // 第三个Ntuple存放能量粒子的y坐标
    analysisManager->FillNtupleDColumn(3,particlePos.z());      // 第四个Ntuple存放能量粒子的z坐标
    analysisManager->AddNtupleRow(); // 添加一行数据

    analysisManager->FillH1(0,edep);        // 将本次Hit的能量沉积添加到直方图中

    // 返回 true，表示该步骤成功生成了一个命中并进行了处理。
    return true;

}

// 每个event开始前运行一次
// 前事件初始化 命中集合，并将该集合注册到 Geant4 的事件命中集合 (G4HCofThisEvent) 中
void G4ImproveSD::Initialize(G4HCofThisEvent* hce){

    // 创建一个新的命中集合 fHitsCollection，用于存储当前事件中所有的命中信息。
    fHitsCollection = new G4ImproveHitsCollection(SensitiveDetectorName,collectionName[0]);

    // 获取命中集合的 ID
    G4int hcID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);

    // 将刚刚创建的命中集合 fHitsCollection 注册到事件的命中集合 hce 中
    hce->AddHitsCollection(hcID,fHitsCollection);
}

// 每个event结束后运行一次。
// 事件结束时，处理和输出敏感探测器的命中信息（Hits）
void G4ImproveSD::EndOfEvent(G4HCofThisEvent*){

    // 获取HitCollection中储存的Hit的个数
    std::size_t nofHits = fHitsCollection->entries();

    G4cout << G4endl
        << "-------->Hits Collection: in this event they are " << nofHits
        << " hits in the tracker chambers: " << G4endl;
    for ( std::size_t i=0; i<nofHits; i++ ) (*fHitsCollection)[i]->Print();
}